"""
安全工具函数

提供密码加密、Token 生成等功能
"""

from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
from typing import Optional
import sys
from pathlib import Path

# 处理导入路径
if __name__ == "__main__" or "." not in __name__:
    sys.path.insert(0, str(Path(__file__).parent.parent.parent))
    from stage2_advanced.chapter02_jwt.config import (
        SECRET_KEY,
        ALGORITHM,
        ACCESS_TOKEN_EXPIRE_MINUTES,
        REFRESH_TOKEN_EXPIRE_DAYS,
    )
else:
    from .config import (
        SECRET_KEY,
        ALGORITHM,
        ACCESS_TOKEN_EXPIRE_MINUTES,
        REFRESH_TOKEN_EXPIRE_DAYS,
    )


# ========== 密码加密上下文 ==========

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


# ========== 密码相关函数 ==========

def hash_password(password: str) -> str:
    """
    加密密码
    
    Args:
        password: 原始密码
        
    Returns:
        bcrypt 哈希值
        
    Example:
        >>> hash_password("Password123")
        '$2b$12$KIXxLVq3qF.ZJKvN3j9IY.VZzGqHZ1xqJ...'
    """
    return pwd_context.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证密码
    
    Args:
        plain_password: 用户输入的密码
        hashed_password: 数据库中的哈希值
        
    Returns:
        密码是否匹配
        
    Example:
        >>> hashed = hash_password("Password123")
        >>> verify_password("Password123", hashed)
        True
        >>> verify_password("WrongPassword", hashed)
        False
    """
    return pwd_context.verify(plain_password, hashed_password)


# ========== JWT Token 相关函数 ==========

def create_access_token(
    data: dict,
    expires_delta: Optional[timedelta] = None
) -> str:
    """
    创建访问令牌（Access Token）
    
    Args:
        data: 要编码的数据（通常包含用户标识）
        expires_delta: 自定义过期时间
        
    Returns:
        JWT Token 字符串
        
    Example:
        >>> token = create_access_token({"sub": "alice"})
        >>> print(token)
        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
    """
    # 复制数据，避免修改原始字典
    to_encode = data.copy()
    
    # 设置过期时间
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    # 添加过期时间到 Payload
    to_encode.update({
        "exp": expire,  # Expiration Time
        "iat": datetime.utcnow(),  # Issued At
    })
    
    # 编码生成 JWT
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    
    return encoded_jwt


def create_refresh_token(data: dict) -> str:
    """
    创建刷新令牌（Refresh Token）
    
    刷新令牌的过期时间更长，用于获取新的访问令牌
    
    Args:
        data: 要编码的数据
        
    Returns:
        JWT Token 字符串
    """
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
    
    to_encode.update({
        "exp": expire,
        "iat": datetime.utcnow(),
        "type": "refresh"  # 标记为刷新令牌
    })
    
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    
    return encoded_jwt


def verify_token(token: str) -> Optional[dict]:
    """
    验证并解码 Token
    
    Args:
        token: JWT Token 字符串
        
    Returns:
        解码后的 Payload，如果验证失败返回 None
        
    Example:
        >>> token = create_access_token({"sub": "alice"})
        >>> payload = verify_token(token)
        >>> print(payload["sub"])
        'alice'
    """
    try:
        # 解码并验证 Token
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
        
    except JWTError:
        # Token 无效或已过期
        return None


def decode_token(token: str) -> Optional[str]:
    """
    从 Token 中提取用户名
    
    Args:
        token: JWT Token 字符串
        
    Returns:
        用户名，如果 Token 无效返回 None
    """
    payload = verify_token(token)
    if payload is None:
        return None
    
    username: str = payload.get("sub")
    return username

